        
// Main header
#include "../Main.h"

//My Header
#include "Element.h"

// Fridge
#include "ExposedVariable.h"
#include "../StringHash.h"
#include "../FridgeScript/FridgeScript.h"
#include "../FileTools.h"

static const u_int uELEMENT_SCRIPT_OUTPUT_BUFFER = 256;
static const u_int uELEMENT_FILE_VERSION = 1;
static const u_int uELEMENT_FILE_HDR = 0xE1E8E67;

Element* Element::s_pxActiveElement = 0;

Element::Element()
{
	m_pxExposedVariables = new TypedList< ExposedVariable >( true );
	m_szName = 0;
	m_szCodeString = 0;
	m_uCodeLength = 0;
	m_bGroup = false;
	m_bLockedControls = false;	// TODO: This should be true; it's false for dev purposes

	for( u_int uScriptOut = 0; uScriptOut < NUM_SCRIPT_OUTPUTS; ++uScriptOut )
	{
		m_aszScriptOutput[uScriptOut] = new char[ uELEMENT_SCRIPT_OUTPUT_BUFFER ];
		memset( m_aszScriptOutput[uScriptOut], 0, sizeof( char ) * uELEMENT_SCRIPT_OUTPUT_BUFFER );
	}
}

Element::Element( const Element* pxElement )
{
	if( pxElement->m_uCodeLength == 0 )
	{
		delete m_szCodeString;
		m_szCodeString = 0;
		m_uCodeLength = 0;
	}
	
	m_pxExposedVariables = new TypedList< ExposedVariable >( true );
	
	m_uCodeLength = pxElement->m_uCodeLength;

	m_szCodeString = new char[ m_uCodeLength + 1 ];

	memcpy( m_szCodeString, pxElement->m_szCodeString, m_uCodeLength );

	m_szCodeString[ m_uCodeLength ] = 0;
}

Element::~Element()
{
	Clear();
}

void Element::Clear()
{
	delete m_szName;
	m_szName = 0;
	delete []m_szCodeString;
	m_szCodeString = 0;
	for( u_int uScriptOut = 0; uScriptOut < NUM_SCRIPT_OUTPUTS; ++uScriptOut )
	{
		delete []m_aszScriptOutput[uScriptOut];
		m_aszScriptOutput[uScriptOut] = 0;
	}
	m_bGroup = false;
	//m_pxExposedVariables = 0;
}


bool Element::ReadFromTemplateFile ( const char* const szFilename )
{
	FILE* pxFile = NULL;
	pxFile = fopen( szFilename, "rb" );
	
	if( !pxFile )
	{
		return false;
	}

	ReadFromFile( pxFile );

	fclose( pxFile );

	return true;
}

bool Element::SaveToTemplateFile ( const char* const szFilename )
{
	FILE* pxFile = NULL;
	pxFile = fopen( szFilename, "wb" );
	
	if( !pxFile )
	{
		return false;
	}

	SaveToFile( pxFile );

	fclose( pxFile );

	return true;
}

bool Element::SaveToFile ( FILE* pxFile )
{
	if( !pxFile )
	{
		return false;
	}

	FileTools::WriteToFile( uELEMENT_FILE_HDR, pxFile );
	FileTools::WriteToFile( uELEMENT_FILE_VERSION, pxFile );
	FileTools::WriteStringToFile( m_szName, pxFile );
	FileTools::WriteStringToFile( m_szCodeString, pxFile );
	FileTools::WriteToFile( m_bGroup, pxFile );

	return true;
}

bool Element::ReadFromFile ( FILE* pxFile )
{
	delete m_szName;
	m_szName = 0;
	delete []m_szCodeString;
	m_szCodeString = 0;
	m_bGroup = false;

	u_int uHdr = 0;
	FileTools::ReadFromFile( uHdr, pxFile );
	if( uHdr != uELEMENT_FILE_HDR )
	{
		return false;
	}
	u_int uVersion = u_int(-1);
	FileTools::ReadFromFile( uVersion, pxFile );
	if( uVersion > uELEMENT_FILE_VERSION )
	{
		return false;
	}

	FileTools::ReadStringFromFile( m_szName, pxFile, true );
	FileTools::ReadStringFromFile( m_szCodeString, pxFile, true );
	FileTools::ReadFromFile( m_bGroup, pxFile );
	
	return true;
}

void Element::AddExposedVariable( const char* szName, const EXPOSED_VARIABLE_TYPE xVariableType, float fInitValue, float fSliderMin, float fSliderMax ) const
{
	ExposedVariable* pxExposedVariable = new ExposedVariable();
	pxExposedVariable->SetName( szName );
	pxExposedVariable->SetValue( fInitValue );
	pxExposedVariable->SetVariableType( xVariableType );
	pxExposedVariable->SetSliderLimits( fSliderMin, fSliderMax );
	
	m_pxExposedVariables->Add( pxExposedVariable );
}

void Element::AddExposedVariable( ExposedVariable* pxExposedVariable )
{
	m_pxExposedVariables->Add( new ExposedVariable( pxExposedVariable ) );
}

void Element::RemoveExposedVariable( int iIndex )
{
	m_pxExposedVariables->Delete( iIndex );
}

ExposedVariable* Element::GetExposedVariable( int iIndex )
{
	return m_pxExposedVariables->Get( iIndex );
}

const ExposedVariable* Element::GetExposedVariable( const char* szName ) const
{
	for( int i = 0; i < (int)m_pxExposedVariables->Count(); i++ )
	{
		const ExposedVariable* pxExposedVariable = m_pxExposedVariables->Get( i );
		
		FAssert( pxExposedVariable != 0 );
				
		if(	GetStringHash( pxExposedVariable->GetName() ) == GetStringHash( szName ) )
		{
			return pxExposedVariable;
		}
	}

	return NULL;
}

int Element::GetNumExposedVariables()
{
	return m_pxExposedVariables->Count();
}

void Element::SetCodeString( const char* szCodeString )
{
	if( !szCodeString || szCodeString[0] == 0 )
	{
		return;
	}

	if( m_szCodeString )
	{
		delete []m_szCodeString;
		m_uCodeLength = 0;
	}

	m_uCodeLength = strlen( szCodeString ) + 1;
	m_szCodeString = new char[ m_uCodeLength ];
	strncpy( m_szCodeString, szCodeString, m_uCodeLength );
}

void Element::Init()
{
	m_bIniting = true;
	s_pxActiveElement = this;
	FridgeScript::ClearScriptOutput();
	FridgeScript::Execute( m_szCodeString, "Init", GetName() );
	strncpy( m_aszScriptOutput[SCRIPT_OUTPUT_INIT], FridgeScript::GetScriptOutput(), uELEMENT_SCRIPT_OUTPUT_BUFFER );
	s_pxActiveElement = 0;
}

void Element::Update()
{
	m_bIniting = false;
	s_pxActiveElement = this;
	FridgeScript::ClearScriptOutput();
	FridgeScript::Execute( m_szCodeString, "Update", GetName() );
	strncpy( m_aszScriptOutput[SCRIPT_OUTPUT_UPDATE], FridgeScript::GetScriptOutput(), uELEMENT_SCRIPT_OUTPUT_BUFFER );
	s_pxActiveElement = 0;
}

void Element::Render()
{
	m_bIniting = false;
	s_pxActiveElement = this;
	FridgeScript::ClearScriptOutput();
	FridgeScript::Execute( m_szCodeString, "Render", GetName() );
	strncpy( m_aszScriptOutput[SCRIPT_OUTPUT_RENDER], FridgeScript::GetScriptOutput(), uELEMENT_SCRIPT_OUTPUT_BUFFER );
	s_pxActiveElement = 0;
}

const Element* Element::GetActiveElement()
{
	return s_pxActiveElement;
}

void Element::SetIsGroup( bool bGroup )
{
	m_bGroup = bGroup;
}

bool Element::IsGroup() const
{
	return m_bGroup;
}

bool Element::IsIniting() const
{
	return m_bIniting;
}

void Element::SetName( const char* szName )
{
	const u_int uMax = 128;

	m_szName = new char[ uMax ];

	strncpy( m_szName, szName, uMax );
}

// eof
